<?php

/**
 * 文本关键字查询
 * User: functions
 * Date: 2016/7/5
 * Time: 16:26
 */
namespace Tools\Word;

class Finder
{
    /**
     * 关键字数据
     * @var array
     */
    protected static $_key_word = ['莫名其妙', '一时时','办证','办证件'];

    /**
     * 关键字树
     * @see https://zh.wikipedia.org/wiki/Trie
     * @var array
     */
    protected static $_key_word_tree = [];

    /**
     * 查询文本
     * @var string
     */
    protected static $_str;

    /**
     * 查询文本数组
     * @var array
     */
    protected static $_str_arr = [];

    /**
     * 匹配出的关键字数组
     * @var array
     */
    protected static $_find_result = [];

    /**
     * 需要替换的位置
     * @var array
     */
    protected static $_replace_position = [];

    public function __construct()
    {
        $filePath = __DIR__ . '/keyword.txt';
        $this->loadKeyWord($filePath);
        $time1 = microtime(true);
        $this->makeKeyWordTree();
        $time2 = microtime(true);
        echo "tree expense time :" . ($time2 - $time1) . "\r\n";
    }

    /**
     * @param $filePath
     */
    protected function loadKeyWord($filePath)
    {
        if(!file_exists($filePath)) {
            throw new \UnexpectedValueException("Invalid KeyWord File");
        }
        $time1 = microtime(true);
        $fp = fopen($filePath, 'r+');
        while(!feof($fp)) {
            $buffer = fgets($fp, 4096);// Gets line from file pointer
            static::$_key_word[] = trim($buffer);
        }
        fclose($fp);
        $time2 = microtime(true);
        echo "file load expense time :" . ($time2 - $time1) . "\r\n";
    }

    /**
     * 分割utf8字符串成数组
     * @param $str
     * @return array
     */
    public static function getChars($str)
    {
        $s = $str;
        $len = strlen($s);
        if($len == 0) {
            return array();
        }
        $chars = array();
        for($i = 0; $i < $len; $i++) {
            $c = $s[$i];
            $n = ord($c);
            $n1 = $n >> 7;
            if($n1 == 0) {        //0xxx xxxx, asci, single
                $chars[] = $c;
            } else {
                $n2 = $n >> 4;
                if($n2 == 15) {    //1111 xxxx, first in four char
                    if($i < $len - 3) {
                        $chars[] = $c . $s[$i + 1] . $s[$i + 2] . $s[$i + 3];
                        $i += 3;
                    }
                } else {
                    $n3 = $n >> 5;
                    if($n3 == 7) {    //111x xxxx, first in three char
                        if($i < $len - 2) {
                            $chars[] = $c . $s[$i + 1] . $s[$i + 2];
                            $i += 2;
                        }
                    } else {
                        $n4 = $n >> 6;
                        if($n4 == 3) {    //11xx xxxx, first in two char
                            if($i < $len - 1) {
                                $chars[] = $c . $s[$i + 1];
                                $i++;
                            }
                        }
                    }
                }
            }
        }
        return $chars;
    }

    /**
     * 生成关键字树
     */
    protected function makeKeyWordTree()
    {
        foreach(static::$_key_word as $words) {
            $chars = static::getChars($words);
            $chars[] = null;    //串结尾字符
            $count = count($chars);
            $T = &static::$_key_word_tree;

            for($i = 0; $i < $count; $i++) {
                $c = $chars[$i];
                if(!array_key_exists($c, $T)) {
                    $T[$c] = array();    //插入新字符，关联数组
                }
                $T = &$T[$c];
            }
        }
        $this->makeFileCache();
    }

    protected function makeFileCache()
    {
        file_put_contents("./tree_key.txt",var_export(static::$_key_word_tree,true));
    }

    /**
     * 忽略的字符
     * @param $char
     * @return bool
     */
    public function skipWord($char)
    {
        $asciiCode = ord($char);
        if($asciiCode == 0) {
            return true;
        }

        if($asciiCode >= 32 && $asciiCode <= 126) {
            return true;
        }
        return false;
    }

    /**
     * 查询
     * @param $str
     * @return array
     */
    public function find($str)
    {
        static::$_str_arr = $chars = static::getChars($str);
        $len = count($chars);
        $len = $len - 1;
        $Tree = &static::$_key_word_tree;

        for($i = 0; $i <= $len; $i++) {
            $c = $chars[$i];
            $temp = [];

            //起始字符匹配
            if(array_key_exists($c, $Tree)) {
                $T = &$Tree[$c];
                $temp[$i] = $c;
                static::$_replace_position[$i] = "*";
                for($j = $i + 1; $j <= $len; $j++) {
                    $c = $chars[$j];

                    if(array_key_exists(null, $T) && count(array_keys($T)) == 1) {
                        break;
                    } else {
                        // 跳过特殊符号
                        while($this->skipWord($c) && $j < $len) {
                            $temp[$j] = $c;
                            $j++;
                            $c = $chars[$j];
                        }
                    }

                    if(!array_key_exists($c, $T)) {
                        break;
                    } else {
                        $temp[$j] = $c;
                        static::$_replace_position[$j] = "*";
                    }

                    $T = &$T[$c];
                }
                static::$_find_result[] = $temp;
            }
        }
        return $this;
    }

    /**
     * @return string
     */
    public function replace()
    {
        if(empty(static::$_str_arr)) {
            return '';
        }
        // 替换
        $result = array_replace(static::$_str_arr, static::$_replace_position);
        return implode("", $result);
    }
}
